﻿// Shader-Based-Image-Processing (SBIP)
// http://code.google.com/p/sbip/
//
// Copyright © Frank Nagl, 2009-2010
// admin@franknagl.de
//
namespace SBIP.Filter
{
    using System;

    /// <summary>
    /// Grayscale image.
    /// </summary>
    /// <remarks><para>The filter grayscales colored and grayscale images.</para>
    /// <para>Sample usage:</para>
    /// <code>
    /// Bitmap image = new Bitmap("cathedral.jpg");
    ///
    /// // 1. Offline rendering of images
    /// // create Processor, used as rendering framework
    /// Processor processor = new Processor( );
    /// // starts Processor
    /// processor.Begin( image );
    /// // create Grayscale filter
    /// Grayscale filter = new Grayscale( );
    /// processor.Filter = filter;
    /// // optional: configure filter
    /// filter.Algorithm = Grayscale.CommonAlgorithms.BT709;
    /// // apply the filter, render to bitmap  
    /// Bitmap resultImage = processor.RenderToBitmap( );
    /// resultImage.Save( "Grayscale.jpg", ImageFormat.Jpeg );
    /// // apply the filter, render to texture
    /// // Texture2D resultTexture = processor.RenderToTexture( );
    /// processor.End( );
    ///  
    /// // 2. Online rendering of videos or images
    /// // create any windows control for rendering in
    /// Form myForm = new Form
    /// {
    ///     Width = 1280,
    ///     Height = 720
    /// };
    /// // starts Processor
    /// processor.Begin( "Video.avi", myForm );
    /// // create Grayscale filter
    /// filter = new Grayscale( );
    /// processor.Filter = filter;
    /// // optional: configure filter
    /// filter.Red = 0.5f;
    /// filter.Green = 0.419f;
    /// filter.Blue = 0.081f;
    /// // apply the filter
    /// myForm.Show( );
    /// while ( myForm.Created )
    /// {
    ///     processor.Render( );
    ///     Application.DoEvents( );
    /// }
    /// processor.End( );
    /// </code>
    /// 
    /// <para><b>Initial image:</b></para>
    /// <img src="../../Cathedral.jpg" width="500" height="338" />
    /// <para><b>Result image (RMY):</b></para>
    /// <img src="../../Grayscale.jpg" width="500" height="338" />
    /// </remarks>
    public sealed class Grayscale : BaseFilter
    {
        /// <summary>
        /// Set of predefined common grayscaling algorithms, 
        /// which have aldready initialized grayscaling coefficients.
        /// </summary>
        public enum CommonAlgorithms
        {
            /// <summary>Grayscale image using BT709 algorithm.</summary>
            BT709,
            /// <summary>Grayscale image using RMY algorithm. </summary>
            RMY,
            /// <summary>Grayscale image using Y algorithm.</summary>
            Y
        }

        #region effect properties
        private CommonAlgorithms algorithm;
        /// <summary>
        /// Defines the grayscale algorithm type. 
        /// See also <seealso cref="CommonAlgorithms"/>.
        /// </summary>
        public CommonAlgorithms Algorithm
        {
            get { return algorithm; }
            set
            {
                if (Effect == null)
                    throw new ArgumentException("Algorithm" + InitMsg);

                algorithm = value;
                PostInit();
            }
        }

        private float red;
        /// <summary>Portion of red channel's value to use during 
        /// conversion from RGB to grayscale. </summary>
        public float Red
        {
            get { return red; }
            set
            {
                if (Effect == null)
                    throw new ArgumentException("Red" + InitMsg);

                red = value;
                Effect.Parameters["Red"].SetValue(value);
            }
        }

        private float green;
        /// <summary>Portion of green channel's value to use during 
        /// conversion from RGB to grayscale. </summary>
        public float Green
        {
            get { return green; }
            set
            {
                if (Effect == null)
                    throw new ArgumentException("Green" + InitMsg);

                green = value;
                Effect.Parameters["Green"].SetValue(value);
            }
        }

        private float blue;
        /// <summary>Portion of blue channel's value to use during 
        /// conversion from RGB to grayscale. </summary>
        public float Blue
        {
            get { return blue; }
            set
            {
                if (Effect == null)
                    throw new ArgumentException("Blue" + InitMsg);

                blue = value;
                Effect.Parameters["Blue"].SetValue(value);
            }
        }
        #endregion effect properties

        /// <summary>
        /// Initializes a new instance of the <see cref="Grayscale"/> class.
        /// </summary>
        public Grayscale() : base("Grayscale") 
        {
            algorithm = CommonAlgorithms.BT709;
        }

        /// <summary>
        /// Defines the RGB coefficients of the grayscale algorithm.
        /// </summary>
        protected override void PostInit()
        {
            switch (algorithm)
            {
                case CommonAlgorithms.BT709:
                    Red = 0.2125f;
                    Green = 0.7154f;
                    Blue = 0.0721f;
                    break;
                case CommonAlgorithms.RMY:
                    Red = 0.5f;
                    Green = 0.419f;
                    Blue = 0.081f;
                    break;
                case CommonAlgorithms.Y:
                    Red = 0.299f;
                    Green = 0.587f;
                    Blue = 0.114f;
                    break;
            }
        }
    }
}
